package io.renren.wechat.support;

import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.crypto.digest.HmacAlgorithm;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;

import java.util.Arrays;
import java.util.Map;
import java.util.Objects;

/**
 * 生成接口签名的工具类
 */
public class SignUtils {

    /**
     * 例如： hmac_sha256(appsecret+X+Y+X+timestamp+appsecret)
     *
     * @param appsecret
     * @param signMethod 默认为：HMAC_SHA256
     * @param paths      对应@PathVariable
     * @param params     对应@RequestParam
     * @param body       对应@RequestBody
     * @return
     */
    public static String sign(String appsecret, String signMethod, String timestamp, String[] paths,
                              Map<String, String[]> params, String body) {
        StringBuilder sb = new StringBuilder(appsecret);

        // path variable（对应@PathVariable）
        if (ArrayUtils.isNotEmpty(paths)) {
            String pathValues = String.join("", Arrays.stream(paths).sorted().toArray(String[]::new));
            sb.append(pathValues);
        }

        // parameters（对应@RequestParam）
        if (MapUtils.isNotEmpty(params)) {
            params.entrySet().stream().filter(entry -> Objects.nonNull(entry.getValue())) // 为空的不计入
                    .sorted(Map.Entry.comparingByKey()).forEach(paramEntry -> {
                String paramValue = String.join("",
                        Arrays.stream(paramEntry.getValue()).sorted().toArray(String[]::new));
                sb.append(paramEntry.getKey()).append(paramValue);
            });
        }

        // body（对应@RequestBody)
        if (StringUtils.isNotBlank(body)) {
            Map<String, Object> map = JSON.parseObject(body, Map.class);
            map.entrySet().stream().filter(entry -> Objects.nonNull(entry.getValue())) // 为空的不计入
                    .sorted(Map.Entry.comparingByKey()).forEach(paramEntry -> {
                sb.append(paramEntry.getKey()).append(paramEntry.getValue());
            });
        }
        sb.append(timestamp).append(appsecret);

        String sign = new String();
        if (StringUtils.isBlank(signMethod) || StringUtils.equalsIgnoreCase(signMethod, "HMAC-SHA256")) {
            sign = new HMac(HmacAlgorithm.HmacSHA256, appsecret.getBytes()).digestHex(sb.toString());
        } else if (StringUtils.equalsIgnoreCase(signMethod, "HMAC")) {
            sign = new HMac(HmacAlgorithm.HmacMD5, appsecret.getBytes()).digestHex(sb.toString());
        } else {
            Digester md5 = new Digester(DigestAlgorithm.MD5);
            sign = md5.digestHex(sb.toString());
        }
        return sign.toUpperCase();
    }
}